# _*_ coding:utf-8 _*_
# @Time  : 2022.06.21
# @Author: zizlee
import sys
import datetime
import json
import time

import requests
import urllib3
from iFinDPy import THS_iFinDLogin, THS_iFinDLogout, THS_DS, THS_BD


urllib3.disable_warnings()


# 进度打印
def print_progress_bar(current, total, color=35, title=''):  # percent是小数
    percent = round(current/total, 4)
    prefix_progress = '▓' * int(80 * percent)
    leave_progress = '▓' * (80 - int(80 * percent))
    # percent = '%.2f' % (percent * 100)
    print(f'\033[1;{color}m{current}/{total}\033[0m|\033[1;{color}m{prefix_progress}\033[0m{leave_progress} {title}')
    sys.stdout.flush()


# 获取各品种的主力合约代码
def get_variety_main_contract(q_date):
    url = 'https://210.13.218.130:9000/v1/ruizy/variety/contract/'
    query = {'m': 1, 'date': q_date.replace('-', '')}
    r = requests.get(url, params=query, verify=False)
    contract_data = r.json()['data']
    return {c['variety_en']: c['scontract'] for c in contract_data}


# 查询数据指标的具体数据
def get_index_information(index_id, page, page_size, use_max=True, use_day=None):
    query = {
        'iid': index_id,
        'page': page,
        'page_size': page_size
    }
    url = 'https://210.13.218.130:9000/v1/datalib/table/info/'
    r = requests.get(url, params=query, verify=False)
    resp_data = r.json()['data']
    # index_info = resp_data['index_info']
    index_data = resp_data['data']
    value = None
    if not index_data:
        return value
    if use_max:
        index_data = sorted(index_data, key=lambda x: x['datadate'], reverse=True)
        value = index_data[0]['datavalue']
    if use_day:
        value = None
        for i_data in index_data:
            if i_data['datadate'] == use_day:
                value = i_data['datavalue']
                break
    return value


# 获取隐含波动率的平值期权代码
def get_implied_option_code(index_item, contracts_dict, query_day):
    contract = contracts_dict.get(index_item['variety_en'])
    value = get_index_information(index_id=index_item['ZLID'], page=1, page_size=60, use_max=True, use_day=query_day)
    if not all([contract, value]):
        print(contract, query_day, value)
        raise ValueError('没有合约或价格数据!', index_item['ZLID'], contract, value)
    # 计算期权平值
    option_value = None
    for rule in index_item['price_rules']:
        if rule['min'] < value <= rule['max']:
            option_value = int(round(value / rule['interval'], 0) * rule['interval'])
            break
    if not option_value:
        raise ValueError('平值期权代码计算错误:', option_value)
    # if index_item['variety_en'] == 'CF':  # 调整合约代码使用
    #     option_value = 17400
    # 期权代码
    option_code = f'{index_item["variety_en"]}{contract}'
    option_code += f'{index_item["interval_symbol"]}{index_item["direction"]}{index_item["interval_symbol"]}'
    option_code += f'{option_value}.{index_item["exchange"]}'
    return option_code


# 保存数据到指标中
def save_data_to_server(sheet_id, datalist):
    url = 'https://210.13.218.130:9000/v1/datalib/table/update/'
    body_data = {
        'dataid': sheet_id,
        'row_value': datalist
    }
    r = requests.post(url, json=body_data, verify=False)
    if r.json().get('code') != 200:
        print('保存出错了', r.json())


def read_index_configs():
    with open('波动率.json', 'r', encoding='utf8') as fp:
        indexes = json.load(fp)
    print('读取更新数量:', len(indexes))
    if POINTERS:
        indexes = list(filter(lambda x: x['source_id'] in POINTERS, indexes))
    if ONLY_OPTION:
        indexes = list(filter(lambda x: x['flag'] == 'us_impliedvol', indexes))
    print('等待更新数量:', len(indexes))
    return indexes


# 处理指标数据
def handle_index_values(index_list):
    # 获取当日主力合约代码
    mq_date = (datetime.datetime.strptime(START, '%Y-%m-%d') + datetime.timedelta(days=1)).strftime('%Y-%m-%d')
    main_contracts = get_variety_main_contract(q_date=mq_date)
    # 覆盖更新合约数据
    for k, v in M_CONTRACTS.items():
        vn, vm = k.split('.')
        if main_contracts.get(vn, '') == vm:
            print('转换', vn, vm, '->', v)
            main_contracts[vn] = v

    main_contracts.update(M_CONTRACTS)
    total_count = len(index_list)
    for i, index_item in enumerate(index_list):
        # print(index_item)
        # 获取当日平值期权代码
        op_code = get_implied_option_code(index_item, contracts_dict=main_contracts, query_day=START)
        if op_code.endswith('.INE'):
            op_code = op_code.replace('.INE', '.SHF')
        print(op_code, START)
        if op_code == 'M2405-C-4000.DCE':
            op_code = 'M2405-C-3900.DCE'
        if op_code == 'M2405-P-4000.DCE':
            op_code = 'M2405-P-3900.DCE'
        if index_item['flag'] == 'us_impliedvol':  # 平值期权隐含波动率
            ret = THS_BD(op_code, 'ths_implied_volatility_option', START)  # 期权隐含波动率
            value = ret.data.iloc[0]['ths_implied_volatility_option']
            value = round(value * 100, 2) if value is not None else value
        elif index_item['flag'] == 'volatilityratio':  # 标的历史波动率
            # 基础数据-期权-标的历史波动率-iFinD数据接口
            ret = THS_BD(op_code, 'ths_anal_volatility_underlying_option', f'{START},{index_item["day_count"]},{ANNUAL_NUMBER}')
            value = ret.data.iloc[0]['ths_anal_volatility_underlying_option']
            value = round(value, 4) if value is not None else value
        else:
            raise ValueError('不支持的数据类型.')
        if index_item['source_id'] in ['R00020697', 'R00020698']:  # 动力煤的平值看涨或跌的期权隐含波动率为0
            value = 0
        if value is None:
            print(f'{op_code},{index_item["name_zh"]} {START}的数据为None.', index_item['source_id'])
            continue
        print(index_item['source_id'], index_item['name_zh'], op_code, START, value)
        # 保存数据
        save_data_to_server(index_item['id'], datalist=[{'datadate': START, 'datavalue': value}])
        # 打印进度
        print_progress_bar(i + 1, total=total_count, color=35, title=index_item['name_zh'])
        time.sleep(0.3)


if __name__ == '__main__':
    ANNUAL_NUMBER = 252   # 年化系数
    ONLY_OPTION = 0  # 只更新期权
    START = '2023-12-12'  # 操作日期
    THS_iFinDLogin('rdqh085', 'rdrj180912')
    # for d in ['2023-10-20', '2023-10-23', '2023-10-24', '2023-10-25', '2023-10-26', '2023-10-27', '2023-10-30',  '2023-10-31', '2023-11-01']:
    # START = d
    POINTERS = []  # 指定指标
    M_CONTRACTS = {
        'AP.401': '403',
        'C.2401': '2405',
        'M.2401': '2405',
        'PP.2401': '2405',
        'P.2401': '2405',
        'V.2401': '2405',
        'L.2401': '2405',
        'PG.2401': '2402',
    }  # 指定品种合约，用于修改平值期权代码的
    handle_index_values(read_index_configs()[29:])  # 处理数据
    THS_iFinDLogout()
